package com.nhncorp.pleiades.persistence;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.Serializable;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;

import org.jgroups.persistence.CannotPersistException;
import org.jgroups.persistence.CannotRemoveException;
import org.jgroups.persistence.CannotRetrieveException;
import org.jgroups.persistence.PersistenceManager;

import com.nhncorp.pleiades.conf.PleiadesConfiguration;

public class ClientSessionStatusPersistence implements PersistenceManager {

  private PleiadesConfiguration conf;

  private final File file;

  public ClientSessionStatusPersistence(String propertiesFilename)
      throws Exception {
    String path = "session_status.dat";
    conf = new PleiadesConfiguration();
    if (conf.getBoolean("pleiades.persistency.multiple", true)) {
      path = conf.get("pleiades.sessiondata.path", path);
      path = path + System.nanoTime();
    }
    file = new File(path);
    file.createNewFile();
  }

  public void save(Serializable key, Serializable val)
      throws CannotPersistException {
    try {
      Map map = retrieveAll();
      map.put(key, val);
      saveAll(map);
    } catch (CannotRetrieveException e) {
      throw new CannotPersistException(e, "Unable to pre-load existing store.");
    }
  }

  public Serializable remove(Serializable key) throws CannotRemoveException {
    Object o;
    try {
      Map map = retrieveAll();
      o = map.remove(key);
      saveAll(map);
    } catch (CannotRetrieveException e) {
      throw new CannotRemoveException(e, "Unable to pre-load existing store.");
    } catch (CannotPersistException e) {
      throw new CannotRemoveException(e, "Unable to pre-load existing store.");
    }
    return (Serializable) o;
  }

  public void saveAll(Map map) throws CannotPersistException {
    try {
      OutputStream fos = new FileOutputStream(file);
      Properties prop = new Properties();
      for (Iterator iterator = map.entrySet().iterator(); iterator.hasNext();) {
        Map.Entry entry = (Map.Entry) iterator.next();
        prop
            .setProperty(entry.getKey().toString(), entry.getValue().toString());
      }
      prop.store(fos, null);
      fos.flush();
      fos.close();
    } catch (IOException e) {
      throw new CannotPersistException(e, "Cannot save to: "
          + file.getAbsolutePath());
    }
  }

  public Map retrieveAll() throws CannotRetrieveException {
    try {
      Properties prop = new Properties();
      FileInputStream fis = new FileInputStream(file);
      prop.load(fis);
      fis.close();
      return filterLoadedValues(prop);
    } catch (IOException e) {
      throw new CannotRetrieveException(e, "Unable to load from file: "
          + file.getAbsolutePath());
    }
  }

  public void clear() throws CannotRemoveException {
    try {
      saveAll(Collections.EMPTY_MAP);
    } catch (CannotPersistException e) {
      throw new CannotRemoveException(e, "Unable to clear map.");
    }
  }

  protected Map filterLoadedValues(Map in) {

    Map<String, Long> out = new HashMap<String, Long>();
    for (Iterator iterator = in.entrySet().iterator(); iterator.hasNext();) {
      Map.Entry entry = (Map.Entry) iterator.next();
      out.put(entry.getKey().toString(), Long.valueOf(entry.getValue()
          .toString()));
    }
    return out;
  }

  public void shutDown() {
    return;
  }

}
